<script setup lang="ts">
import { markRaw, nextTick, ref, watch, onMounted, onUnmounted } from 'vue'
import { VueFlow, useVueFlow } from '@vue-flow/core'
import type { Dimensions, Elements } from '@vue-flow/core'
import { Background } from '@vue-flow/background'
import { Controls } from '@vue-flow/controls'
import {LoadingBar} from 'vue-amazing-ui'
import StartNode from '@/components/vue-flow/nodes/start-node.vue'
import EndNode from '@/components/vue-flow/nodes/end-node.vue'
import LLMNode from '@/components/vue-flow/nodes/LLM-node.vue'
import CodeNode from '@/components/vue-flow/nodes/code-node.vue'
import KnowledgeNode from '@/components/vue-flow/nodes/knowledge-node.vue'
import ApiNode from '@/components/vue-flow/nodes/api-node.vue'
import textNode from '@/components/vue-flow/nodes/text-node.vue'
import IfNode from '@/components/vue-flow/nodes/if-node.vue'
import DebuggerNode from '@/components/vue-flow/nodes/DebuggerNode.vue'
import { Test_data } from '@/lib/constant'
import PluginList from '@/components/vue-flow/plugin-list.vue'
import KnowLedgeList from '@/components/vue-flow/knowledge-list.vue'
import storeMap from '@/pina/index'
import { getQueryParam } from '@/lib/utils'
import { getWorkFlow } from '@/api/index'
import { cloneDeep } from 'lodash'
interface Node {
  id: string
  label: string
  position: { x: number; y: number }
}
interface Edge {
  id: string
  source: string
  target: string
}
const elements = ref<Elements>()
const customLoadingBar = ref()
const nodeTypes = {
  start: markRaw(StartNode),
  end: markRaw(EndNode),
  'module': markRaw(LLMNode),
  code: markRaw(CodeNode),
  'knowledge': markRaw(KnowledgeNode),
  'plugin': markRaw(ApiNode),
  text: markRaw(textNode),
  'selector': markRaw(IfNode),
  'debugger': markRaw(DebuggerNode)
}
const nodesTemplte = {
  nodes: [
    {
      id: 'start_1',
      type: 'start',
      label: 'start',
      position: { x: 25, y: 400 }
    },
    {
      id: 'end_1',
      type: 'end',
      label: 'end',
      position: { x: 1000, y: 400 }
    },
    // {
    //   id: 'debugger_1',
    //   type: 'debugger',
    //   label: 'debugger',
    //   position: { x: 1450, y: 400 }
    // }
  ]
}
const { findNode, nodes, edges, addNodes, addEdges, project, vueFlowRef, onConnect, setNodes, setEdges, setViewport, removeNodes, getViewport,getNodes,getEdges,fitView } =
  useVueFlow(nodesTemplte)
  // const viewport = getViewport()
  // console.log(viewport.zoom) // 当前缩放级别
onConnect((params) => {
  addEdges(params)
})
function handleOnDrop(event: DragEvent) {
  const type = event.dataTransfer?.getData('application/vueflow')
  if (type === 'workflow') {
    const { nodes, edges, position, zoom } = Test_data
    const [x = 0, y = 0] = position
    setNodes(nodes)
    setEdges(edges)
    setViewport({ x, y, zoom: zoom || 0 })
    return
  }
  if (type === 'plugin') {
    const DialogStore = storeMap.useDialogStore()
    DialogStore.open(
      {
        clientX: event.clientX,
        clientY: event.clientY
      },
      type
    )
    return
  }
  addNewNode(
    {
      clientX: event.clientX,
      clientY: event.clientY
    },
    type
  )
}
const type2String = (type: string | undefined) => {
  if (type == 'plugin') {
    return 'plugin_'
  } else if (type == 'knowledge') {
    return 'knowledge_'
  } else if (type == 'module') {
    return 'module_'
  } else if (type == 'selector') {
    return 'selector_'
  } else {
    return type
  }
}
const type2StoreName = (type: string | undefined) => {
  if (type == 'plugin') {
    return 'usePluginStore'
  } else if (type == 'knowledge') {
    return 'useKnowLedgeStore'
  } else if (type == 'module') {
    return 'useLLMStore'
  }else if (type == 'end') {
    return 'useEndStore'
  } else if (type == 'selector') {
    return 'useIfStore'
  } else {
    return 'useStartStore'
  }
}
const addNewNode = (positionXY: { clientX: number; clientY: number }, type: string | undefined) => {
  const { left, top } = vueFlowRef.value!.getBoundingClientRect()

  const position = project({
    x: positionXY.clientX - left,
    y: positionXY.clientY - top
  })
  const idVal = type2String(type) + (nodes.value.length + 1).toString()
  const newNode = {
    id: idVal,
    type,
    position,
    label: `${type} 节点`,
    data: {
      title: type,
    }
  }
  addNodes(cloneDeep([newNode]))
  if(type!=='debugger'){
    storeMap[type2StoreName(type)] && storeMap[type2StoreName(type)]().setId(idVal)
  }

  nextTick(() => {
    const node = findNode(newNode.id)
    const stop = watch(
      () => node!.dimensions,
      (dimensions: Dimensions) => {
        if (dimensions.width > 0 && dimensions.height > 0 && node) {
          node.position = {
            x: node.position.x - node.dimensions.width / 2,
            y: node.position.y - node.dimensions.height / 2
          }
          stop()
        }
      },
      { deep: true, flush: 'post' }
    )
  })
}
function handleOnDragOver(event: DragEvent) {
  event.preventDefault()

  if (event.dataTransfer) {
    event.dataTransfer.dropEffect = 'move'
  }
}
const selectedNode = ref({})
// const edges = ref([]);
const onNodeClick = (event: MouseEvent) => {
  checkNodeEdges(event?.node.id)
}
const degbuggerStore = storeMap.useDebuggerStore();
 


watch(()=>degbuggerStore.debuggerRes,(n,o)=>{
  if(n){
    showDebuggerInof(n)
      customLoadingBar.value.finish();
      degbuggerStore.addNodeLoading(false)
  }
})
const showDebuggerInof =(n)=>{
  const currentNode = getNodes.value.find(node => node.id === 'end_1');
      // const {x,y} = position
      if (currentNode) {
        const currentPosX = currentNode.position.x;
        const currentPosY = currentNode.position.y;
        const newNodePosition = {
          x: currentPosX + 500,
          y: currentPosY,
        };
        const newNode = {
          id: `debugger`,
          type: 'debugger',
          position: newNodePosition,
          data: {
            title: 'debugger',
            output: [{
              ref: '',
              name: 'output',
              type: 'debugger',
              value: n
            }]
          },
        };
        //
        nodesv.value[nodesv.value.length-1].type!== 'debugger'?nodesv.value.push(newNode):(nodesv.value[nodesv.value.length-1]=newNode)
      }
}
watch(()=>degbuggerStore.debuggerLoading,(n,o)=>{
  if(n){
    customLoadingBar.value.start();
    // degbuggerStore.addNodeLoading(false)
  }else{
    customLoadingBar.value.error();
  }
},{
  deep:true
})
const onEdgeAdded = (event: MouseEvent, edge: Edge) => {
  console.log(event, edge)
}
const onEdgeRemoved = (event: MouseEvent, edge: Edge) => {
  console.log(event, edge)
}
const onNodeRemoved = (event: MouseEvent, edge: Edge) => {
  console.log(event, edge)
}
const checkNodeEdges = (nodeId: string) => {
  const hasEdges = edges.value.some((edge: Edge) => edge.source === nodeId || edge.target === nodeId)
  if (hasEdges) {
    console.log(`Node ${nodeId} has edges.`)
  } else {
    console.log(`Node ${nodeId} does not have any edges.`)
  }
}
watch(
  () => storeMap.useDialogStore().addNodeFlag,
  (addNodeFlag) => {
    if (addNodeFlag) {
      const flag = addNodeFlag
      const position = storeMap.useDialogStore().position
      const nodeType = storeMap.useDialogStore().nodeType
      if (flag) {
        addNewNode(position, nodeType)
        storeMap.useDialogStore().setAddNodeFlag(false)
      }
    }
  }
)

const code = getQueryParam('code')
const nodesv = ref([
  ...nodesTemplte.nodes
])
const edgesv = ref([])
const getWorkFlowList = async () => {
  const res = await getWorkFlow({ code })
  if (res.data?.content) {
    const dataWorkFlow = JSON.parse(res.data.content)
  
    const { nodes: nodesData, edges: edgesdata } = dataWorkFlow;
    const pluginArray = [];
    const moduleArray = [];
    const selectorArray = [];
    const knowledgeArray = [];
    // nodesData.pop();
    nodesData.map(item => {
      const nodedata = item;
      switch (item.type) {
        case 'start':
          storeMap.useStartStore().init(nodedata)
          break;
        case 'plugin':
          // storeMap.usePluginStore().init(nodedata)
          pluginArray.push(nodedata)
          break;
        case 'module':
          // moduleArray.push(nodedata)
          storeMap.useLLMStore().init(nodedata)
          break;
        case 'end':
          storeMap.useEndStore().init(nodedata)
          break;
        case 'selector':
          storeMap.useIfStore().init(nodedata)
          // selectorArray.push(nodedata)
          break;
        case 'knowledge':
          // knowledgeArray.push(nodedata)
          storeMap.useKnowLedgeStore().init(nodedata)
          break;
        default:
          storeMap.useStartStore().init(nodedata)
      }
    })
    pluginArray.length&&storeMap.usePluginStore().init(pluginArray)
    // moduleArray.length&&storeMap.useLLMStore().init(moduleArray)
    // storeMap.useIfStore().init(selectorArray)
    // storeMap.useKnowLedgeStore().init(knowledgeArray)
    // useVueFlow({nodes:nodesData,edges:edgesdata})
    nodesv.value = [...nodesData]
    edgesv.value = [...edgesdata]
  }
}
onMounted(() => {
  getWorkFlowList();
  fitView({ padding: 5, duration: 800 })
})
const getDeletedLinesNode=(target:any,nodeList:any,edgesList:any)=>{
  edgesList.map(item=>{
    if(item.source==target){
      !nodeDependencies.includes(item.target)&&
        nodeList.push(item.target)
        getDeletedLinesNode(item.target,nodeList,edgesList)
    }
  })
}
let nodeDependencies =[]
const onEdgesChange = (changes) => {
      changes.forEach((change) => {
        if (change.type === 'remove') {
          // 获取被删除的连线
          // console.log(change,getEdges.value,'------------------')
          const {target} = change;
          !nodeDependencies.includes(target)&&nodeDependencies.push(target)
          getDeletedLinesNode(target,nodeDependencies,getEdges.value)
          // const deletedEdge = getEdges().find(edge => edge.id === change.id);
          // // 判断是否是左侧连线
          // if (deletedEdge && isLeftSideConnection(deletedEdge)) {
          //   console.log('左侧连线被删除', deletedEdge);
          // }
          nodeDependencies.map(item=>{
            const storeName = type2StoreName(item.split('_')[0])
            storeMap[storeName] && storeMap[storeName]().clearData()
          })
        }
      });
      
    };
    const defaultEdgeOptions = {
  type: 'default', // 默认边的类型
  markerEnd: {
    type: 'arrow',  // 设置连线终点的箭头类型
    width: 36,             // 箭头宽度
    height: 36,            // 箭头高度
    strokeWidth: 1,        // 箭头边框宽度
    // color: '#ff5733',      // 箭头颜色
  },
}
</script>

<template>
  <div class="relative h-full w-full" id="main-canvas" @drop="handleOnDrop" @dragover="handleOnDragOver">
    <PluginList />
    <KnowLedgeList />
    <VueFlow v-model="elements" :node-types="nodeTypes" @node-click="onNodeClick" @edge-added="onEdgeAdded"
      @node:remove="onNodeRemoved" :nodes="nodesv" :edges="edgesv" @edgesChange="onEdgesChange"
      :defaultEdgeOptions="defaultEdgeOptions"
      >
      <Controls />
      <Background />
    </VueFlow>
    <LoadingBar
    ref="customLoadingBar"
    :loading-bar-size="5"
    color-loading="#2db7f5"
    color-finish="#52c41a"
    color-error="magenta"
  />
  </div>
</template>

<style>
@import '@vue-flow/core/dist/style.css';
@import '@vue-flow/core/dist/theme-default.css';
@import '@vue-flow/controls/dist/style.css';

#main-canvas {
  --vf-handle: hsl(var(--primary));

  .vue-flow__handle {
    width: 18px;
    height: 18px;
  }
}

.vue-flow__node.selected {
  /* 选中节点样式 */
  outline: 1px solid var(--light-usage-primary-color-primary, #4d53e8) !important;
  border-radius: 8px;
}
</style>
